/*
 * Reprice.cpp
 *
 *  Created on: Dec 4, 2009
 *      Author: abhishek
 */

#include "Reprice.h"

Reprice::Reprice() {
	for (int i = 0; i < NUMNODES; i++) {

		nodeIdToNodePtrIndex_[i] = new Node();
		heapNodesIndex_[i] = new heapNode();
		//		isNodeVisited_[i] = 0 ;
		//		bestDelta_[i] = 0.000;
		//		bestMaxRevenue_[i] = 0.00 ;
		//		iterationNumber_[i] = 0 ;
		strategy1[i].isNodeVisited = 0;
		strategy1[i].iterationNumber = 0;
		strategy1[i].bestDelta = 0.00;
		strategy1[i].bestMaxRevenue = 0.00;
	}
	totalRevenue_ = 0.0000;

}
Reprice::~Reprice() {
}

void Reprice::selectCandidates() {

	for (int i = 0; i < TOPK; i++) {
		heapNodesIndex_[i]->nodeIdIs(i);
		heapNodesIndex_[i]->gRevenueIs(gRevenue_[i]);
		queue_.push(heapNodesIndex_[i]);
		//		cout << "gValue = " << gRevenue_[i] << endl ;
	}

	for (int i = TOPK; i < NUMNODES; i++) {
		if (gRevenue_[i] > (queue_.top())->gRevenue()) {
			queue_.pop();
			heapNodesIndex_[i]->nodeIdIs(i);
			heapNodesIndex_[i]->gRevenueIs(gRevenue_[i]);
			queue_.push(heapNodesIndex_[i]);
		}
		//		cout << "gValue = " << gRevenue_[i] << endl ;
	}

	// At this point I have the TOPK candidate sets.
	for (int i = TOPK - 1; i >= 0; i--) {
		heapNode* n = queue_.top();
		queue_.pop();
		candidateNodes[i] = n->nodeId();
		cout << "candidate: " << candidateNodes[i] << endl;
		cout << "gValue = " << n->gRevenue() << endl;
	}
}
void Reprice::heuristic1() {

	cout << "Start strategy1" << endl;

	selectCandidates();

	bool flag = true;
	bool nodeExists = false;

	for (int iter = 1; iter <= NUMNODES; iter++) {

		cout << "iteration = " << iter << endl;
		flag = true;
		nodeExists = false;

		int bestNodeId = -1;
		double bestDelta = 0.00;
		double bestMaxRevenue = 0.00;

		for (int k = 0; k < TOPK; k++) {
			int nodeId = candidateNodes[k];
			//		for (int nodeId = 0; nodeId < NUMNODES; nodeId++) {
			//			cout << "Node id = " << nodeId << endl ;
			if (strategy1[nodeId].isNodeVisited == 0) {
				//				cout << "NOT VISITED: Node id = " << nodeId << endl ;
				double currentBestDelta = 0.00;
				double currentBestMaxRevenue = 0.00;
				Node* n = nodeIdToNodePtrIndex_[nodeId];

				n->influentialNodeRevenue(currentBestDelta,
						currentBestMaxRevenue, nodeIdToNodePtrIndex_);

				if (currentBestMaxRevenue > bestMaxRevenue + EPSILON) {
					bestMaxRevenue = currentBestMaxRevenue;
					bestDelta = currentBestDelta;
					bestNodeId = nodeId;
				}

				nodeExists = true;
			}
		}

		if (!nodeExists) {
			cout << "NO NODE EXISTS!" << endl;
			break;
		}

		if (bestMaxRevenue > 0 + EPSILON) {
			if (bestNodeId < 0) {
				cout << "ERROR: best node id = " << bestNodeId << endl;
			}
			double newRevenue = totalRevenue_;

			strategy1[bestNodeId].isNodeVisited = 1;
			strategy1[bestNodeId].bestMaxRevenue = bestMaxRevenue;
			strategy1[bestNodeId].bestDelta = bestDelta;

			strategy1[bestNodeId].iterationNumber = iter;
			Node* n = nodeIdToNodePtrIndex_[bestNodeId];

			strategy1[bestNodeId].originalPrice = n->price();
			strategy1[bestNodeId].originalRevenue = totalRevenue_;

			//			cout << "total revenue" << totalRevenue_ << " : " ;
			newRevenue -= n->revenue();
			newRevenue -= n->revenueGOfNeighbours(nodeIdToNodePtrIndex_);
			n->updateAtributes(bestDelta, nodeIdToNodePtrIndex_);
			newRevenue += n->revenue();
			newRevenue += n->revenueGOfNeighbours(nodeIdToNodePtrIndex_);

			strategy1[bestNodeId].newRevenue = newRevenue;

			//			cout << totalRevenue_ <<" : " << newRevenue << endl ;
			//			printf("+%.10f : +%.10f ", totalRevenue_, newRevenue);
			cout << endl;
			totalRevenue_ = newRevenue;
			cout << bestNodeId << ": " << bestDelta << ": " << bestMaxRevenue
					<< endl;

		} else {
			break;
		}

	}

	writetoFile(HEURISTIC1);
}

void Reprice::heuristic2() {
	cout << "Start strategy2" << endl;

	selectCandidates();

	bool flag = true;
	bool nodeExists = false;

	for (int iter = 1; iter <= NUMNODES; iter++) {

		cout << "Iteration number " << iter << endl << endl << endl << endl;
		flag = true;
		nodeExists = false;

		int bestNodeId = -1;
		int bestNodeId2 = -1;
		double bestDelta = 0.00;
		double bestDelta2 = 0.00;
		double bestMaxRevenue = 0.00;

		int nodeId = 0;
		int nodeId2 = 0;

		//		for (nodeId = 0; nodeId < NUMNODES; nodeId++) {
		for (int k = 0; k < TOPK; k++) {
			nodeId = candidateNodes[k];

			if ((strategy1[nodeId].isNodeVisited == 1))
				continue;
			for (int l = k + 1; l < TOPK; l++) {
				nodeId2 = candidateNodes[l];
				//			for (nodeId2 = nodeId + 1; nodeId2 < NUMNODES; nodeId2++) {
				if (strategy1[nodeId2].isNodeVisited == 0) {
					cout << nodeId << ":" << nodeId2 << endl;
					double currentBestDelta = 0.00;
					double currentBestDelta2 = 0.00;
					double currentBestMaxRevenue = 0.00;
					Node* n = nodeIdToNodePtrIndex_[nodeId];
					Node* n2 = nodeIdToNodePtrIndex_[nodeId2];

					n->influentialEdgeRevenue(n2, currentBestDelta,
							currentBestDelta2, currentBestMaxRevenue,
							nodeIdToNodePtrIndex_);

					if (currentBestMaxRevenue > bestMaxRevenue + EPSILON) {
						bestMaxRevenue = currentBestMaxRevenue;
						bestDelta = currentBestDelta;
						bestDelta2 = currentBestDelta2;
						bestNodeId = nodeId;
						bestNodeId2 = nodeId2;
					}
					nodeExists = true;
				}
			}
		}

		if (!nodeExists)
			break;

		if (bestMaxRevenue > 0 + EPSILON) {
			double newRevenue = totalRevenue_;
			Node* n = nodeIdToNodePtrIndex_[bestNodeId];
			Node* n2 = nodeIdToNodePtrIndex_[bestNodeId2];

			strategy1[bestNodeId].isNodeVisited = 1;
			strategy1[bestNodeId].bestMaxRevenue = bestMaxRevenue;
			strategy1[bestNodeId].bestDelta = bestDelta;
			strategy1[bestNodeId].iterationNumber = iter;
			strategy1[bestNodeId].originalPrice = n->price();
			strategy1[bestNodeId].originalRevenue = totalRevenue_;

			strategy1[bestNodeId2].isNodeVisited = 1;
			strategy1[bestNodeId2].bestMaxRevenue = bestMaxRevenue;
			strategy1[bestNodeId2].bestDelta = bestDelta2;
			strategy1[bestNodeId2].iterationNumber = iter;
			strategy1[bestNodeId2].originalPrice = n2->price();
			strategy1[bestNodeId2].originalRevenue = totalRevenue_;

			// Update the two nodes attributes..

			newRevenue -= n->revenue();
			newRevenue -= n2->revenue();
			//			newRevenue -= n->revenueNeighboursuv(n2, nodeIdToNodePtrIndex_);
			newRevenue -= n->revenueGOfNeighboursExceptV(nodeIdToNodePtrIndex_,
					n2->nodeId());
			newRevenue -= n2->revenueGOfNeighboursExceptV(
					nodeIdToNodePtrIndex_, n->nodeId());

			n->updateAtributes(n2, bestDelta, bestDelta2, nodeIdToNodePtrIndex_);
			n2->updateAtributes(n, bestDelta2, bestDelta, nodeIdToNodePtrIndex_);

			newRevenue += n->revenue();
			newRevenue += n2->revenue();
			//			newRevenue += n->revenueNeighboursuv(n2, nodeIdToNodePtrIndex_);

			newRevenue += n->revenueGOfNeighboursExceptV(nodeIdToNodePtrIndex_,
					n2->nodeId());
			newRevenue += n2->revenueGOfNeighboursExceptV(
					nodeIdToNodePtrIndex_, n->nodeId());

			strategy1[bestNodeId].newRevenue = newRevenue;
			strategy1[bestNodeId2].newRevenue = newRevenue;

			printf("%.10f : %.10f ", totalRevenue_, newRevenue);
			cout << endl;
			totalRevenue_ = newRevenue;

			cout << bestNodeId << ": " << bestDelta << ": " << bestNodeId2
					<< ": " << bestDelta2 << ": " << bestMaxRevenue << endl;
		} else {
			break;
		}

	}

	writetoFile(HEURISTIC2);
}

void Reprice::heuristic3() {

	//	map<string, trianglesOverlapNode*> trianglesOverlapMap ;
	//	priority_queue< trianglesOverlapNode*, vector<trianglesOverlapNode*>, Comparator > queueTrianglesOverlap_ ;

	double previousTotalRevenue = 0.001;
	double currentTotalRevenue = totalRevenue_;

	int count = 1;
	int iterationNumber = 0 ;
	while (!queueTrianglesOverlap_.empty()) {
		iterationNumber++;
//		if (count == TOPK)
//			break;

		trianglesOverlapNode* edge = queueTrianglesOverlap_.top();
		queueTrianglesOverlap_.pop();

		cout << "weight = " << edge->weight() << endl ;
		Node* n = nodeIdToNodePtrIndex_[edge->u()];
		Node* n2 = nodeIdToNodePtrIndex_[edge->v()];

		if  ( (strategy1[edge->u()].isNodeVisited == 1) || (strategy1[edge->v()].isNodeVisited == 1) ){
			// ASSUMPTION:
			// I am not sure whether this assumption is good???
			// Once price for a node is set.. I dont change the price if that node...
			// Not even in conjunction with other nodes...
			continue ;
		}


		double bestDelta = 0.00;
		double bestDelta2 = 0.00;
		double bestMaxRevenue = 0.00;
		n->influentialEdgeRevenue(n2, bestDelta, bestDelta2,
				bestMaxRevenue, nodeIdToNodePtrIndex_);


		if (bestMaxRevenue > EPSILON) {
			double newRevenue = currentTotalRevenue;

			strategy1[edge->u()].isNodeVisited = 1;
			strategy1[edge->u()].bestMaxRevenue = bestMaxRevenue;
			strategy1[edge->u()].bestDelta = bestDelta;
			strategy1[edge->u()].iterationNumber = iterationNumber;
			strategy1[edge->u()].originalPrice = n->price();
			strategy1[edge->u()].originalRevenue = currentTotalRevenue;

			strategy1[edge->v()].isNodeVisited = 1;
			strategy1[edge->v()].bestMaxRevenue = bestMaxRevenue;
			strategy1[edge->v()].bestDelta = bestDelta2;
			strategy1[edge->v()].iterationNumber = iterationNumber;
			strategy1[edge->v()].originalPrice = n2->price();
			strategy1[edge->v()].originalRevenue = currentTotalRevenue;

			// Update the two nodes attributes..

			newRevenue -= n->revenue();
			newRevenue -= n2->revenue();
			//			newRevenue -= n->revenueNeighboursuv(n2, nodeIdToNodePtrIndex_);
			newRevenue -= n->revenueGOfNeighboursExceptV(nodeIdToNodePtrIndex_,
					n2->nodeId()); // edge->v()
			newRevenue -= n2->revenueGOfNeighboursExceptV(
					nodeIdToNodePtrIndex_, n->nodeId()); // edge->u()

			n->updateAtributes(n2, bestDelta, bestDelta2, nodeIdToNodePtrIndex_);
			n2->updateAtributes(n, bestDelta2, bestDelta, nodeIdToNodePtrIndex_);

			newRevenue += n->revenue();
			newRevenue += n2->revenue();
			//			newRevenue += n->revenueNeighboursuv(n2, nodeIdToNodePtrIndex_);

			newRevenue += n->revenueGOfNeighboursExceptV(nodeIdToNodePtrIndex_,
					n2->nodeId());
			newRevenue += n2->revenueGOfNeighboursExceptV(
					nodeIdToNodePtrIndex_, n->nodeId());

			strategy1[edge->u()].newRevenue = newRevenue;
			strategy1[edge->v()].newRevenue = newRevenue;

			printf("%.10f : %.10f ", totalRevenue_, newRevenue);
			cout << endl;
			totalRevenue_ = newRevenue;
			currentTotalRevenue = newRevenue;

			cout << edge->u() << ": " << bestDelta << ": " << edge->v()
					<< ": " << bestDelta2 << ": " << bestMaxRevenue << endl;


			// If the increase in revenue is < MINPERCENTAGECHANGE% then quit.
			if (currentTotalRevenue > previousTotalRevenue + EPSILON) {
				double relativeChange = ((currentTotalRevenue
						- previousTotalRevenue) / previousTotalRevenue)
						* 100.000;
				if (relativeChange < MINPERCENTAGECHANGE)
					break;
			}
			previousTotalRevenue = currentTotalRevenue;
		}

//		else {
//			count++;
//		}
	}

		 writetoFile(HEURISTIC3);
}
void Reprice::readGraph() {

	updateF();
	updateG();
	updatePrice();
	updateInfluence();

	// update total revenue
	for (int nodeId = 0; nodeId < NUMNODES; nodeId++) {
		Node* n = nodeIdToNodePtrIndex_[nodeId];
		totalRevenue_ += n->revenue();
		gRevenue_[nodeId] = n->gRevenue();
//		n->printNeighbours();

	}
	//	cout << "totalRevenue_ = " << totalRevenue_ << endl ;

	constructTrianglesOverlap();
}

void Reprice::constructTrianglesOverlap() {

	int id1 = 0;
	int id2 = 0;
	char buffer[33];
	map<int, double>::iterator it;
	map<string, trianglesOverlapNode*>::iterator iterTriangles;

	vector<int>::iterator intersectionIterator;
	vector<int> setIntersectionOutput(2 * NUMNODES);

	for (int i = 0; i < NUMNODES; i++) {
		Node* n = nodeIdToNodePtrIndex_[i];
		map<int, double> edgeMap = n->guv();

		for (it = edgeMap.begin(); it != edgeMap.end(); ++it) {
			id1 = n->nodeId();
			id2 = it->first;
			if (id1 > id2) {
				int temp = id1;
				id1 = id2;
				id2 = temp;
			}

			sprintf (buffer, "%d", id1);

			string key(buffer) ;
			key+="#" ;
			sprintf (buffer, "%d", id2);
			key = key + buffer ;
//			cout << "key = " << key << endl ;

			iterTriangles = trianglesOverlapMap.find(key);
			if (iterTriangles == trianglesOverlapMap.end()) { // this key does not exist in the map
			//				map<string, trianglesOverlapNode*> trianglesOverlapMap ;
				trianglesOverlapNode* n = new trianglesOverlapNode();
				n->uIs(id1);
				n->vIs(id2);
				double revenue = 0.00;
				revenue += nodeIdToNodePtrIndex_[id1]->revenue();
				revenue += nodeIdToNodePtrIndex_[id2]->revenue();
				revenue
						+= nodeIdToNodePtrIndex_[id1]->revenueGOfNeighboursExceptV(
								nodeIdToNodePtrIndex_, id2);
				revenue
						+= nodeIdToNodePtrIndex_[id2]->revenueGOfNeighboursExceptV(
								nodeIdToNodePtrIndex_, id1);
				n->revenueAcrossEdgesIs(revenue);
				int sizeIntersection = 0 ;
				set<int> neighbour1 = nodeIdToNodePtrIndex_[id1]->neighbours();
				set<int> neighbour2 = nodeIdToNodePtrIndex_[id2]->neighbours();
				sizeIntersection = neighbour1.size() + neighbour2.size();
//				cout << "a = " << neighbour1.size() << endl ;
//				cout << "b = " << neighbour2.size() << endl ;
//				nodeIdToNodePtrIndex_[id1]->printNeighbours();
//				nodeIdToNodePtrIndex_[id2]->printNeighbours();
				set<int>::iterator setIter;
				for (setIter = neighbour2.begin(); setIter != neighbour2.end(); ++setIter) {
					neighbour1.insert(*setIter);
				}
				sizeIntersection -= neighbour1.size();
//				cout << "a union b = " << neighbour1.size() << endl ;
				n->numTrianglesIs(sizeIntersection);
				n->weightIs(((double) n->numTriangles())
						* n->revenueAcrossEdges());
				cout << n->u() << "#" << n->v() << "::" << n->numTriangles() << ": " << n->revenueAcrossEdges() << " : " << n->weight() << endl ;
				queueTrianglesOverlap_.push(n);
				trianglesOverlapMap[key] = n;
			}
		}
	}

}
void Reprice::updateF() {

	string line;
	ifstream myfile(FFILENAME);

	int nodeId = 0;
	double f = 0.0000;
	if (myfile.is_open()) {
		do {
			myfile >> nodeId;
			myfile >> f;
			Node* n = nodeIdToNodePtrIndex_[nodeId];
			n->nodeIdIs(nodeId);
			n->fIs(f);
			//			cout << "node id =  "  << n->nodeId() << " f = " << n->f() << endl;
			//			printf("f = %f \n", n->f() );
		} while (!myfile.eof());
		myfile.close();
	}

}

void Reprice::updateG() {
	string line;
	ifstream myfile(GFILENAME);

	int nodeId = 0;
	int nodeId2 = 0;
	double gVal = 0.0000;
	if (myfile.is_open()) {
		do {
			myfile >> nodeId;
			myfile >> nodeId2;
//			cout << nodeId << ":::::" << nodeId2 << endl ;
			myfile >> gVal;
			Node* n = nodeIdToNodePtrIndex_[nodeId];
			n->guvAdd(nodeId2, gVal);
//						cout << "node id =  "  << n->nodeId()<< ": input nodeId = "<< nodeId << " guvg = " << n->guvg(nodeId2) << endl;

		} while (!myfile.eof());
		myfile.close();
	}
}

void Reprice::updatePrice() {
	string line;
	ifstream myfile(PRICEFILENAME);

	int nodeId = 0;
	int price = 0;
	if (myfile.is_open()) {
		do {
			myfile >> nodeId;
			myfile >> price;
			Node* n = nodeIdToNodePtrIndex_[nodeId];
			double p = (double) price;

			n->priceIs(p);
			//						cout << "node id =  "  << n->nodeId() << " price = " << n->price() << endl;
		} while (!myfile.eof());
		myfile.close();
	}
}

void Reprice::updateInfluence() {
	string line;
	ifstream myfile(INFLUENCEFILENAME);

	int nodeId = 0;
	double influence = 0;
	if (myfile.is_open()) {
		do {
			myfile >> nodeId;
			myfile >> influence;
			Node* n = nodeIdToNodePtrIndex_[nodeId];
			n->influenceIs(influence);
			//			cout << "node id =  "  << n->nodeId() << " influence = " << n->influence() << endl;
		} while (!myfile.eof());
		myfile.close();
	}
}

void Reprice::writetoFile(string filename) {
	cout << "WRITER CALLED !!" << endl;
	ofstream myfile;
	myfile.open(filename.c_str());

	for (int nodeId = 0; nodeId < NUMNODES; nodeId++) {
		//		cout << nodeId << "\t";
		//		cout << strategy1[nodeId].iterationNumber << "\t";
		//		cout << strategy1[nodeId].originalPrice << "\t";
		//		cout << strategy1[nodeId].originalRevenue << "\t";
		//		cout << strategy1[nodeId].newRevenue << "\t";
		//		cout << strategy1[nodeId].bestDelta << "\t";
		//		cout << strategy1[nodeId].bestMaxRevenue << endl;

		if (strategy1[nodeId].isNodeVisited) {

			cout << nodeId << "\t";
			cout << strategy1[nodeId].iterationNumber << "\t";
			cout << strategy1[nodeId].originalPrice << "\t";
			cout << strategy1[nodeId].originalRevenue << "\t";
			cout << strategy1[nodeId].newRevenue << "\t";
			cout << strategy1[nodeId].bestDelta << "\t";
			cout << strategy1[nodeId].bestMaxRevenue << endl;

			myfile << nodeId << "\t";
			myfile << strategy1[nodeId].iterationNumber << "\t";
			myfile << strategy1[nodeId].originalPrice << "\t";
			myfile << strategy1[nodeId].originalRevenue << "\t";
			myfile << strategy1[nodeId].newRevenue << "\t";
			myfile << strategy1[nodeId].bestDelta << "\t";
			myfile << strategy1[nodeId].bestMaxRevenue << endl;
		}
	}
	myfile.close();
}
